// +build js,wasm

package jsgo

import (
	"strings"
)

type JsDom struct {
	JsObject
}

func (q *JsDom) Len() int {
	return q.value.Length()
}

func (q *JsDom) available() bool {
	return q.JsObject.available() && q.Len() > 0
}

func (q *JsDom) attr(attrName string) string {
	if !q.available() {
		return ""
	}
	v := q.value.Index(0)
	attr := v.Get(attrName)
	return MustStr(attr)
}

func (q *JsDom) Attr(attrName string) string {
	if !q.available() {
		return ""
	}
	v := q.value.Index(0)
	attr := v.Call("getAttribute", attrName)
	return MustStr(attr)
}

func (q *JsDom) SetAttr(attrName, attrValue string) {
	if !q.available() {
		return
	}
	v := q.value.Index(0)
	v.Call("setAttribute", attrName, attrValue)
}

func (q *JsDom) setAttr(attrName string, value interface{}) {
	if !q.available() {
		return
	}
	v := q.value.Index(0)
	v.Set(attrName, value)
}

func (q *JsDom) Val() string {
	return q.attr("value")
}

func (q *JsDom) SetVal(value string) {
	q.setAttr("value", value)
}

func (q *JsDom) Html() string {
	return q.attr("innerHTML")
}

func (q *JsDom) SetHtml(html string) {
	q.setAttr("innerHTML", html)
}

func (q *JsDom) Text() string {
	return q.attr("innerText")
}

func (q *JsDom) SetText(text string) {
	q.setAttr("innerText", text)
}

func (q *JsDom) HasClass(className string) bool {
	if len(className) == 0 {
		return false
	}
	class := strings.ReplaceAll(q.Attr("class"), "\t", " ")
	classes := strings.Split(class, " ")
	for _, class := range classes {
		if class == className {
			return true
		}
	}
	return false
}

func (q *JsDom) AddClass(className string) {
	if len(className) == 0 {
		return
	}
	var finalClass string
	var appendClass = func(c string) {
		if len(finalClass) > 0 {
			finalClass = strJoin(finalClass, " ")
		}
		finalClass = strJoin(finalClass, c)
	}

	class := strings.ReplaceAll(q.Attr("class"), "\t", " ")
	classes := strings.Split(class, " ")
	hasClass := false
	for _, class := range classes {
		if class == className {
			hasClass = true
		}
		appendClass(class)
	}
	if !hasClass {
		appendClass(className)
	}
	q.setAttr("class", finalClass)
}

func (q *JsDom) RemoveClass(className string) {
	if len(className) == 0 {
		return
	}
	class := strings.ReplaceAll(q.Attr("class"), "\t", " ")
	classes := strings.Split(class, " ")
	var finalClass string
	for _, class := range classes {
		if len(class) == 0 || className == class {
			continue
		}
		if len(finalClass) > 0 {
			finalClass = finalClass + " "
		}
		finalClass = finalClass + class
	}
	q.SetAttr("class", finalClass)
}

func (q *JsDom) Each(fun func(dom *JsDom, index int)) {
	if !q.available() || fun == nil {
		return
	}
	for i := 0; i < q.Len(); i++ {
		q := &JsDom{JsObject{
			value: q.value.Index(i),
		}}
		fun(q, i)
	}
}

func (q *JsDom) Remove() {
	q.value.Call("remove")
}

func (q *JsDom) attrDom(attr string) *JsDom {
	return &JsDom{JsObject{
		value: q.value.Index(0).Get(attr),
	}}
}

func (q *JsDom) Parent() *JsDom {
	if !q.available() {
		return &JsDom{}
	}

	p := q.attrDom("parentElement")
	if p.Len() == 0 {
		p = q.attrDom("parentNode")
	}
	return p
}

func (q *JsDom) Children() *JsDom {
	if !q.available() {
		return &JsDom{}
	}
	c := q.attrDom("childNodes")
	if c.Len() == 0 {
		c = q.attrDom("children")
	}
	return c
}

func (q *JsDom) Find(selector string) *JsDom {
	return &JsDom{JsObject{
		value: q.value.Call("querySelectorAll", selector),
	}}
}
